﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace vAddins
{
    public class Manifest
    {
        internal const string FileName = "vAddin.xml";

        internal XmlDocument doc;

        XmlElement root;
        XmlElement name;
        XmlElement vers;
        XmlElement desc;
        XmlElement auth;
        XmlElement refs;
        XmlElement reqs;

        public Manifest(string file)
        {
            doc = new XmlDocument();
            doc.Load(file);

            root = doc["vAddin"];
            name = root["Name"];
            vers = root["Version"];
            desc = root["Description"];
            auth = root["Author"];
            refs = root["References"];
            reqs = root["Requirements"];

            if (name == null) throw new XmlException("The root node of a vAddin manifest file must contain a \"Name\" node which contains the name of the vAddin.\r\nPlease look at the example manifest file in the vAddins assembly!");
            if (vers == null) throw new XmlException("The root node of a vAddin manifest file must contain a \"Version\" node which contains a valid System.Version (string) of the vAddin.\r\nPlease look at the example manifest file in the vAddins assembly!");

            Name = root["Name"].InnerXml;

            if (desc != null) Description = desc.InnerXml;

            if (auth != null) Author = auth.InnerText;

            Version version;
            var versSuccess = System.Version.TryParse(vers.InnerXml, out version);
            if (versSuccess) Version = version;
            else throw new FormatException("The \"Version\" node of a vAddin must contain a valid System.Version (string).");

            References = new List<Reference>();

            if (refs != null && refs.HasChildNodes) foreach (XmlNode e in refs.ChildNodes) References.Add(new Reference(e));

            if (reqs != null && reqs.HasChildNodes)
                foreach (XmlNode e in reqs.ChildNodes)
                    switch (e.Name)
                    {
                        case "AddinRequirement":
                            if (e.Attributes.Count != 1 || e.Attributes["path"] == null) throw new XmlException("All nodes within the \"References\" node must only have a \"path\" attribute.\r\nPlease look at the example manifest file in the vAddins assembly!");
                            if (e.InnerXml != string.Empty) throw new XmlException("All nodes within the \"References\" node must have no content (must be empty).\r\nPlease put the reference path in the \"path\" attribute.\r\nPlease look at the example manifest file in the vAddins assembly!");

                            References.Add(new Reference(ReferenceType.System, e.Attributes["path"].Value));
                            break;
                        default:
                            throw new XmlException("Invalid tag identified within the vAddin's Requirements node.\r\nPlease look at the example manifest file in the vAddins assembly!");
                    }
        }

        public string Name { get; internal set; }
        public string Description { get; internal set; }

        public string Author { get; internal set; }

        public Version Version { get; internal set; }

        public List<Reference> References { get; internal set; }
    }
}
